import { observe } from "./observe";
import Dep from "./observe/dep";
import Watcher, { nextTick } from "./observe/watcher";

// 初始化状态
export function initState(vm) {
  const opts = vm.$options;
  if (opts.data) {
    // 如果有data就初始化data
    initData(vm);
  }
  if (opts.computed) {
    // 如果有computed就初始化computed
    // computed本质就是一个代理dirty属性的watcher
    initComputed(vm);
  }
  if (opts.watch) {
    initWatch(vm);
  }
}

// 初始化data
function initData(vm) {
  // data可能是对象/函数
  let data = vm.$options.data;
  // 获取真正的data
  data = typeof data === 'function' ? data.call(vm) : data;
  // 复制一份引用给_data,这样vm身上就有代理过的data了
  vm._data = data;
  // 对数据进行劫持
  observe(data);
  // 为了能直接vm.name,而不是vm._data.name
  // 所以要代理一下这个vm._data
  for (let key in data) {
    proxy(vm, '_data', key);
  }
}

// 劫持目标数据的get/set,返回/设置目标值
function proxy(vm, target, key) {
  Object.defineProperty(vm, key, {
    get() {
      return vm[target][key];
    },
    set(newValue) {
      if (vm[target][key] === newValue) return;
      vm[target][key] = newValue;
    }
  })
}

// 初始化计算属性
function initComputed(vm) {
  const computed = vm.$options.computed;
  // 记录当前实例的所有watcher保存到vm上
  const watchers = vm._computedWatchers = {};
  for (let key in computed) {
    let userDef = computed[key];
    // 监控计算属性中get的变化
    const getter = typeof userDef === 'function' ? userDef : userDef.get;
    // 加个lazy不要立刻执行,取值的时候再执行
    watchers[key] = new Watcher(vm, getter, {
      lazy: true
    });
    defineComputed(vm, key, userDef);
  }
}
// 定义计算属性
function defineComputed(target, key, userDef) {
  const setter = userDef.set || function () { };
  Object.defineProperty(target, key, {
    get: createComputedGetter(key),
    set: setter
  })
}
function createComputedGetter(key) {
  // 检测是否要执行这个getter
  return function () {
    // 获取对应属性的watcher
    const watcher = this._computedWatchers[key]
    if (watcher.dirty) {
      // 如果是脏的,就执行用户的getter
      watcher.evaluate();
    }
    if (Dep.target) {
      // 计算属性出栈后还有渲染watcher,应该让此属性也去收集上层watcher
      watcher.depend();
    }
    return watcher.value;
  }
}

// 初始化watch
function initWatch(vm) {
  const data = vm.$options.watch;
  for (let key in data) {
    // 3种情况字符串,数组,函数
    const handler = data[key];
    if (Array.isArray(handler)) {
      handler.forEach(watch => {
        createWather(vm, key, watch);
      })
    } else {
      createWather(vm, key, handler);
    }
  }
}
// 创建watch
function createWather(vm,key,handler) {
  if(typeof handler === 'string'){
    handler = vm[handler];
  }
  return vm.$watch(key,handler);
}

export function initStateMixin(Vue){
Vue.prototype.$nextTick = nextTick;

// 底层就是哪怕watch是写在options里的也会转成$watch的形式
Vue.prototype.$watch = function (exprOrFn, cb, options = {}) {
  // { deep: true , immediate: true }
  // user:true代表用户自己写的watcher
  // exprOrFn里的值变化了直接执行cb即可
  new Watcher(this,exprOrFn,{user:true},cb);
}
}